﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.ComponentModel;
using System.Xml;
using System.Collections;
using System.Windows.Markup;

namespace Vision.Core.ActivityComponents.SharePoint
{
	/// <summary>
	/// Connects to SharePoint and gets a ListItem's attachment collection
	/// </summary>
	[System.ComponentModel.Designer(typeof(SPListGetAttachmentsDesigner))]
	[ContentProperty("Body")]
	public partial class SPListGetAttachments : NativeActivity
	{
		Variable<IEnumerator> valueEnumerator;
		CompletionCallback onChildComplete;

		/// <summary>
		/// 
		/// </summary>
		[DefaultValue("")]
		[Category("Input")]
		public InArgument<string> ListName { get; set; }

		/// <summary>
		/// 
		/// </summary>
		[DefaultValue("")]
		[Category("Input")]
		public InArgument<string> ListItemId { get; set; }

		/// <summary>
		/// 
		/// </summary>
		[DefaultValue("")]
		[Category("Input")]
		public InArgument<string> Where { get; set; }
		
		/// <summary>
		/// 
		/// </summary>
		[DefaultValue("")]
		[Category("Input")]
		public InArgument<string> OrderBy { get; set; }

		/// <summary>
		/// 
		/// </summary>
		[DefaultValue(null)]
		[Category("Output")]
		public OutArgument<List<Attachment>> Attachments { get; set; }

		/// <summary>
		/// 
		/// </summary>
		[Browsable(false)]
		[DefaultValue(null)]
		[DependsOn("Attachments")]
		public ActivityAction<Attachment> Body { get; set; }
		
		/// <summary>
		/// 
		/// </summary>
		public SPListGetAttachments() : base()
		{
			this.valueEnumerator = new Variable<IEnumerator>();
			this.Body = new ActivityAction<Attachment>()
			{
				Argument = new DelegateInArgument<Attachment>()
				{
					Name = "attachment"
				}
			};
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		protected override void Execute(NativeActivityContext context)
		{
			List<object> methodParams = new List<object>();

			methodParams.Add(this.ListName.Get(context));
			methodParams.Add(this.ListItemId.Get(context));
			
			Components.DynamicWebService spService = (Components.DynamicWebService)context.Properties.Find("F1634880-5000-11E0-A748-B487DFD72085");
			if (spService != null)
			{
				XmlElement result = spService.InvokeMethod<XmlElement>("GetAttachmentCollection", methodParams);
				if (result != null)
				{
					List<Attachment> attachments = result.GetElementsByTagName("Attachment").Cast<XmlNode>().Select
					(
						n => new Attachment()
						{
							Url = n.InnerText,
							FileName = System.IO.Path.GetFileName(n.InnerText),
							FileExtension = System.IO.Path.GetExtension(n.InnerText)
						}
					).ToList();

					if (!string.IsNullOrEmpty(this.Where.Get(context)))
					{
						try
						{
							attachments = System.Linq.Dynamic.DynamicQueryable.Where(attachments.AsQueryable(), this.Where.Get(context), null).ToList();
						}
						catch (Exception ex)
						{
							// do nothing
						}
					}

					if (!string.IsNullOrEmpty(this.OrderBy.Get(context)))
					{
						try
						{
							attachments = System.Linq.Dynamic.DynamicQueryable.OrderBy(attachments.AsQueryable(), this.OrderBy.Get(context), null).ToList();
						}
						catch (Exception ex)
						{
							// do nothing
						}
					}

					this.Attachments.Set(context, attachments);
				}
				this.valueEnumerator.Set(context, this.Attachments.Get(context).GetEnumerator());
			}
			
			IEnumerator attachmentEnumerator = this.valueEnumerator.Get(context);
			if (this.Body == null || this.Body.Handler == null)
			{
				while (attachmentEnumerator.MoveNext())
				{
					// do nothing
				};
				OnForEachComplete(attachmentEnumerator);
				return;
			}
			InternalExecute(context, attachmentEnumerator);
		}


		/// <summary>
		/// 
		/// </summary>
		private CompletionCallback OnChildComplete
		{
			get
			{
				if (this.onChildComplete == null)
				{
					this.onChildComplete = new CompletionCallback(GetStateAndExecute);
				}

				return this.onChildComplete;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="metadata"></param>
		protected override void CacheMetadata(NativeActivityMetadata metadata)
		{
			RuntimeArgument listNameArgument = new RuntimeArgument("ListName", typeof(string), ArgumentDirection.In, true);
			metadata.Bind(this.ListName, listNameArgument);
			metadata.AddArgument(listNameArgument);

			RuntimeArgument listItemIdArgument = new RuntimeArgument("ListItemId", typeof(string), ArgumentDirection.In, true);
			metadata.Bind(this.ListItemId, listItemIdArgument);
			metadata.AddArgument(listItemIdArgument);

			RuntimeArgument whereArgument = new RuntimeArgument("Where", typeof(string), ArgumentDirection.In, false);
			metadata.Bind(this.Where, whereArgument);
			metadata.AddArgument(whereArgument);

			RuntimeArgument orderbyArgument = new RuntimeArgument("OrderBy", typeof(string), ArgumentDirection.In, false);
			metadata.Bind(this.OrderBy, orderbyArgument);
			metadata.AddArgument(orderbyArgument);

			RuntimeArgument attachmentsArgument = new RuntimeArgument("Attachments", typeof(List<Attachment>), ArgumentDirection.Out);
			metadata.Bind(this.Attachments, attachmentsArgument);
			metadata.AddArgument(attachmentsArgument);
			metadata.AddDelegate(this.Body);
			metadata.AddImplementationVariable(this.valueEnumerator);
		}
		
		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		/// <param name="completedInstance"></param>
		private void GetStateAndExecute(NativeActivityContext context, ActivityInstance completedInstance)
		{
			IEnumerator valueEnumerator = this.valueEnumerator.Get(context);
			InternalExecute(context, valueEnumerator);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		/// <param name="valueEnumerator"></param>
		private void InternalExecute(NativeActivityContext context, IEnumerator valueEnumerator)
		{
			if (!valueEnumerator.MoveNext())
			{
				OnForEachComplete(valueEnumerator);
				return;
			}

			// After making sure there is another value, let's check for cancelation
			if (context.IsCancellationRequested)
			{
				context.MarkCanceled();
				OnForEachComplete(valueEnumerator);
				return;
			}

			context.ScheduleAction(this.Body, (Attachment)valueEnumerator.Current, this.OnChildComplete);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="valueEnumerator"></param>
		private void OnForEachComplete(IEnumerator valueEnumerator)
		{
			IDisposable disposable = (valueEnumerator as IDisposable);
			if (disposable != null)
			{
				disposable.Dispose();
			}
		}
	}
}
